feat: add runtime read-only control-plane commands#1797
Conversation
Add CLI-only get and list commands for runtimes, runtime versions, and runtime endpoints with Harness-style pagination, output, injected Core clients, fixtures, and command coverage.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## refactor #1797 +/- ##
============================================
- Coverage 93.61% 93.25% -0.37%
============================================
Files 117 128 +11
Lines 6708 7013 +305
============================================
+ Hits 6280 6540 +260
- Misses 428 473 +45 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
AlexanderRichey
left a comment
There was a problem hiding this comment.
Great work on this. I think we should make two changes before merging. First, I think runtime should show in the RouterScreen, even though the TUI isn't there yet. I don't think it's worth it to carve out a special case for runtime when, in the next CR, we'll have to reverse it. Second, I think we should streamline the tests to be more consistent. We now have run(), which manually sets up mocks, and runFixture(), which returns golden file mocks. Let's only use the golden file testing pattern, if possible. So run() should become what runFixture() is and we'll just have to generate fixtures for the couple missing cases. You might have to just create a bunch of runtimes, versions, and endpoints to make this work easily when running the tests in record mode.
| () => command.commands.map((c) => ({ name: c.name(), description: c.description() })), | ||
| () => | ||
| command.commands | ||
| .filter((command) => command.name() !== "runtime") |
There was a problem hiding this comment.
I understand that we haven't built the TUI for Runtime yet, but still I don't think it's worth introducing this edge case. After we build the TUI in the next CR, the original code will work as intended. Even now, I think what would happen is that the help screen would be shown, which is also fine for now.
|
|
||
| export function createRuntimeVersionHandler(core: Core, io: AppIO): Router { | ||
| return new Router("version", "inspect AgentCore Runtime versions") | ||
| .default(createHelpDefault(io)) |
There was a problem hiding this comment.
This makes sense for now, but it will be replaced by withTui().
| const frame = r.lastFrame()!; | ||
| expect(frame).toContain("harness"); | ||
| expect(frame).toContain("manage agentcore harnesses"); | ||
| expect(frame).not.toContain("runtime"); |
There was a problem hiding this comment.
I think we want the main screen to show runtime.
| describe("runtime control reads", () => { | ||
| test("gets a Runtime and renders the complete response", async () => { | ||
| const result = await run(["runtime", "get", "--id", "runtime-1"]); | ||
|
|
There was a problem hiding this comment.
Is there a reason why we're not doing golden file testing for some of these cases? I think that would be both simpler and more robust.
There was a problem hiding this comment.
This test now uses matchGolden()
| .send(new ListAgentRuntimesCommand({ nextToken, maxResults })); | ||
| } | ||
|
|
||
| async listRuntimeVersions( |
There was a problem hiding this comment.
I see this follows the existing pattern, but what do think of avoiding positional arguments for functions with many arguments? I've found that using input objects makes it easier to handle optional args, and easier to read at the callsite.
There was a problem hiding this comment.
I agree an input object would make this method easier to read in isolation, particularly with the optional pagination fields. I kept the positional signature intentionally because these Runtime methods directly mirror the existing Harness Core interface. Changing only Runtime would leave two different conventions for otherwise parallel APIs. I would prefer to keep them consistent in this PR and, if we decide input objects are the better convention, refactor both Core clients together.
| flag("qualifier", "the endpoint name (qualifier)", z.string().optional()), | ||
| ], | ||
| handle: async (ctx, flags) => { | ||
| if (!flags.id) { |
There was a problem hiding this comment.
I remember this being brought up, but I can't remember. Why exactly can't we make these fields required in the schema to have zod validate this for us?
There was a problem hiding this comment.
Technically, I think we could make them required today for Runtime because there is no TUI yet (will be the next PR). The reason not to is how the router supports future TUI commands.
A required schema:
z.string()
becomes a mandatory Commander option. Commander rejects a bare command before middleware or the handler runs:
agentcore runtime endpoint get
But once runtime has TUI support, that bare command must reach withTuiOnEmptyFlagsAndArgs, which opens the selector screen. So, Harnerss uses optional schemas and validates inside the headless handler. I kept the same schema and headless validation pattern as the next change will be the TUI.
There was a problem hiding this comment.
thanks that makes sense.
| expect(JSON.parse(stdout).agentRuntimeId).toBe(FIXTURE_RUNTIME_ID); | ||
| }); | ||
|
|
||
| test("lists two Runtime pages with Harness pagination names", async () => { |
There was a problem hiding this comment.
what do you mean by harness pagination names here?
There was a problem hiding this comment.
I meant here that Runtime uses the same user-facing pagination flags as Harness, --max-results and --next-token. The test name is unclear because this is the standard pagination, so I renamed it to paginates Runtime list with --max-results and --next-token.
| expect(JSON.parse(secondPage).agentRuntimes).toHaveLength(1); | ||
| }); | ||
|
|
||
| test("maps the endpoint qualifier for a service-valid long Runtime ID", async () => { |
There was a problem hiding this comment.
what is a long runtime Id?
There was a problem hiding this comment.
“Long” was unclear. I meant a service-generated Runtime ID exceeding the 48-character Runtime name limit. Valid IDs can exceed that limit because the service appends a generated suffix. Thanks for this call out I renamed the test and explicitly assert that the fixture ID is longer than 48 characters.
Investigated the Codecov gap. All 44 uncovered changed lines are in the private |
Description
Adds project-free, command-line access to inspect AgentCore Runtimes:
runtime getandruntime listruntime version getandruntime version listruntime endpoint getandruntime endpoint listThe commands follow the Harness handler/Core structure, use the existing JSON output path, and expose one-page pagination through
--max-resultsand--next-token. Endpoint lookup uses--qualifier, mapped to the control-planeendpointName.Runtime appears in the root TUI command menu, and bare Runtime groups print help until their TUI routes are implemented. Runtime TUI workflows, invocation, mutations, project or deployment resolution, tags and policies, agent-card operations, logs, and traces are outside this change.
Related Issue
N/A
Documentation PR
N/A. README command examples are included in this PR.
Type of Change
Testing
Verified from current HEAD
73434193:bun test --coverage --coverage-reporter=lcov(254 passed, 0 failed)bun test --coverage(254 passed, 0 failed; 93.64% functions, 96.11% lines; Runtime Core and handlers 100%)bun test src/handlers/runtime src/core(30 passed, 0 failed)bun run lint:checkprettier --checkbun run typecheckbun run buildbun run compile(all six targets)Additional verification from Runtime-handler-equivalent commit
22634e54:bun run format:checkbun auditbun pm packruntime logsandruntime tracesgroupsus-west-2The committed Runtime fixtures were recorded with
AWS_PROFILE=e2e-testfrom shared E2E account685197708687. The dedicated Runtimeagentcore_cli_runtime_read_only_fixture-wZ7V4Q6vhxis retained with versions1and2plusDEFAULTandruntimeReadOnlyFixtureendpoints for repeatable team recording. The fixture set contains no deploy-account identifiers or credential material.Live read-command verification used an existing Runtime and did not mutate it. Subsequent commits change root TUI visibility and tests/fixtures only; the Runtime handlers and Core are unchanged from that live verification.
Checklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.